package service

import (
	"bufio"
	"encoding/json"
	"fmt"
	log "github.com/sirupsen/logrus"
	"os/exec"
	"regexp"
	"strings"
	"usbipproxy/domain/vo"
)

type UsbIpServerWindowsCmdServiceImpl struct{}

func (u *UsbIpServerWindowsCmdServiceImpl) UnBind(busId string) (bool, error) {
	cmds := []string{"usbipd", "unbind", "-b", busId}
	log.Infof("UsbIpServerWindowsCmdServiceImpl UnBind cmds:%+v", cmds)
	str, err := exec.Command(cmds[0], cmds[1:]...).CombinedOutput()
	if err != nil {
		log.Errorf("UsbIpServerWindowsCmdServiceImpl err:%v str:%v", err, string(str))
		return false, err
	}
	log.Infof("UsbIpServerWindowsCmdServiceImpl ret:%v", string(str))
	return true, nil
}

func (u *UsbIpServerWindowsCmdServiceImpl) Bind(busId string) (bool, error) {
	cmds := []string{"usbipd", "bind", "-b", busId}
	log.Infof("UsbIpServerWindowsCmdServiceImpl Bind cmds:%+v", cmds)
	str, err := exec.Command(cmds[0], cmds[1:]...).CombinedOutput()
	if err != nil {
		log.Errorf("UsbIpAttachList err:%v str:%v", err, string(str))
		return false, err
	}
	log.Infof("UsbIpAttachList ret:%v len(str):%d", string(str), len(str))
	/*
		if !strings.Contains(string(str), "complete") {
			return false, nil
		}
	*/
	if len(str) > 0 {
		return false, nil
	}
	return true, err
}

/*
C:\Windows\System32>usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
4-1    3535:6300  USB 大容量存储设备                                            Not shared
4-5    0e0f:0003  USB 输入设备                                                  Not shared

Persisted:
GUID                                  DEVICE

usbipd: warning: USB filter 'EUsbHubFilter' is known to be incompatible with this software; 'bind --force' will be required.
usbipd: warning: Unknown USB filter 'usbip2_filter' may be incompatible with this software; 'bind --force' may be required.

C:\Windows\System32>
*/
func (u *UsbIpServerWindowsCmdServiceImpl) List() []*vo.UsbInfo {
	str, err := exec.Command("usbipd", "list").CombinedOutput()
	if err != nil {
		log.Errorf("UsbIpList err:%v str:%v", err, string(str))
		return nil
	}

	result := parseUSBInfo(string(str))

	resultByte, _ := json.Marshal(result)
	log.Infof("UsbIpServerWindowsCmdServiceImpl List: %+v", string(resultByte))
	return result
}

func NewUsbIpServerWindowsCmdServiceImpl() UsbIpServerCmdService {
	return &UsbIpServerWindowsCmdServiceImpl{}
}

func parseUSBInfo(input string) []*vo.UsbInfo {
	scanner := bufio.NewScanner(strings.NewReader(input))
	var devices []*vo.UsbInfo

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" ||
			strings.HasPrefix(line, "BUSID") ||
			strings.HasPrefix(line, "GUID") ||
			strings.HasPrefix(line, "usbipd:") ||
			strings.HasPrefix(line, "Connected:") ||
			strings.HasPrefix(line, "Persisted:") {
			continue
		}

		// 使用正则表达式匹配设备行格式
		re := regexp.MustCompile(`^(\d+-\d+)\s+([0-9a-fA-F]{4}):([0-9a-fA-F]{4})\s+(.*?)\s+(Shared|Not shared|Attached)$`)
		matches := re.FindStringSubmatch(line)

		if len(matches) == 6 {
			state := 0
			if matches[5] == "Shared" {
				state = 1
			} else if matches[5] == "Attached" {
				state = 2
			}

			vendor := "unknown vendor"
			product := "unknown product"
			rets := strings.Split(matches[4], ",")
			if len(rets) == 2 {
				vendor = rets[0]
				//product = rets[1]
				product = matches[4]
			} else if len(rets) == 1 {
				//product = rets[0]
				product = matches[4]
			}

			devices = append(devices, &vo.UsbInfo{
				BusId:    matches[1],
				VendorId: fmt.Sprintf("%v:%v", matches[2], matches[3]),
				//Product:    matches[3],
				Vendor:  vendor,
				Product: product,
				State:   state,
			})
		}
	}

	return devices
}
